/*
-----------------------------------------------------------------------------
This source file is part of the
   ___                 __    __ _ _    _ 
  /___\__ _ _ __ ___  / / /\ \ (_) | _(_)
 //  // _` | '__/ _ \ \ \/  \/ / | |/ / |
/ \_// (_| | | |  __/  \  /\  /| |   <| |
\___/ \__, |_|  \___|   \/  \/ |_|_|\_\_|
      |___/                              
      Tutorial Framework
      http://www.ogre3d.org/tikiwiki/
-----------------------------------------------------------------------------
*/
#include "GameApp.h"
#include <OgreStringConverter.h>


//-------------------------------------------------------------------------------------
GameApp::GameApp(void)
{
}
//-------------------------------------------------------------------------------------
GameApp::~GameApp(void)
{
}
//-------------------------------------------------------------------------------------
void GameApp::createScene(void)
{
	
	

	// Set the ambient light
	mSceneMgr->setAmbientLight(Ogre::ColourValue::White);
//-------------------------------------------------------------------------------------	
/*------
* Camera
-------*/
	mCamera->setPosition(0, 30, 0);
	mCamera->lookAt(0, 30, 0);
	mCamera->getDirection();
//-------------------------------------------------------------------------------------
#pragma region Torch

	Ogre::Light* torch = mSceneMgr->createLight("Torch");
	torch->setType(Ogre::Light::LT_SPOTLIGHT);
	torch->setDiffuseColour(0.0, 1.0, 0);
	torch->setSpecularColour(0.0, 0.5, 0);
	torch->setDirection(mCamera->getDirection());
	torch->setPosition(mCamera->getPosition());
	torch->setSpotlightRange(Ogre::Degree(20), Ogre::Degree(60));
	torch->setVisible(false);
	/*	Attenuation:
	*	Range - distance before light has no effect on objects
	*	Constant - 0.0 increase brightness, >0.0 descrease brightness
	*	Linear - >0.0 light fades faster over distance (straight line)
	*	Quadratic - >0.0 light fades faster over distance (angle from source)
	*
	*	att = const + lin * dist + quad * dist^2
	*	----------------------------------------
	*	Need to be up close to a shape for full luminosity of torch
	*	Remove line below to have infinite luminosity
	*/
	torch->setAttenuation(200, 1.0, 0.022, 0.0019);

#pragma endregion Torch
//-------------------------------------------------------------------------------------
#pragma region Player

	player		= mSceneMgr->createEntity("Player", "HideAndSeekPlayer.mesh");
	playerNode	= mSceneMgr->getRootSceneNode()->createChildSceneNode("PlayerNode");	
	playerNode->attachObject(player);
	playerNode->attachObject(mCamera);
	playerNode->attachObject(torch);
	
	Ogre::AxisAlignedBox pBox = player->getBoundingBox();
	playerNode->setPosition(0, -pBox.getCorner(Ogre::AxisAlignedBox::FAR_LEFT_BOTTOM).y, 0);
	playerNode->showBoundingBox(true);

#pragma endregion Player
//-------------------------------------------------------------------------------------

	 

}
//-------------------------------------------------------------------------------------
void GameApp::createFrameListener(void)
{
	BaseApplication::createFrameListener();

	// Populate the camera container
	mCamNode = mCamera->getParentSceneNode();
 
	// set the rotation and move speed
	mRotate = 0.13;
	mMove = 250;

	mDirection = Ogre::Vector3::ZERO;
}
//-------------------------------------------------------------------------------------
bool GameApp::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	if(!processInput(evt))
		return false;
	if(mWindow->isClosed())
		return false;
	if(mShutDown)
		return false;

	mKeyboard->capture();
	mMouse->capture();
	mTrayMgr->frameRenderingQueued(evt);

	mCamNode->translate(mDirection * evt.timeSinceLastFrame, Ogre::Node::TS_WORLD);
	

    return true;
}
//-------------------------------------------------------------------------------------
bool GameApp::processInput(const Ogre::FrameEvent& evt)
{
	static bool mMouseDown = false;


	// toggle current mouse state on Left Mouse Button click
	bool currMouse = mMouse->getMouseState().buttonDown(OIS::MB_Left);

	// If LMB down and mMouseDown is true (!mMouseDown == true)
	if(currMouse && !mMouseDown)
	{
		// Get spotlight object
		// set invisible
		Ogre::Light* mTorch = mSceneMgr->getLight("Torch");
		mTorch->setVisible(!mTorch->isVisible());
	}

	// set mouse down to current mouse state for next frame
	mMouseDown = currMouse;
	
#pragma region Keyboard Controls
	Ogre::Vector3 newDir = Ogre::Vector3(0, 0, 1);
	Ogre::Vector3 yAxis = Ogre::Vector3(0, 1, 0);
	if(mKeyboard->isKeyDown(OIS::KC_W))
	{
		mDirection = mCamNode->getOrientation() * newDir * -mMove;
		//if (pBox->intersection(hiddenBox)){
		//	MessageBox(NULL, NULL, NULL, NULL);
		//}
	}
	if(mKeyboard->isKeyDown(OIS::KC_S))
	{
		mDirection = mCamNode->getOrientation() * newDir * mMove;
	}
	if(mKeyboard->isKeyDown(OIS::KC_A))
	{
		mDirection = (mCamNode->getOrientation() * newDir).crossProduct(yAxis) * mMove;
	}
	if(mKeyboard->isKeyDown(OIS::KC_D))
	{
		mDirection = (mCamNode->getOrientation() * newDir).crossProduct(yAxis) * -mMove;
	}
	

#pragma endregion Keyboard Controls


	return true;
}
//--------------------------------- OIS::KeyListener ----------------------------------
bool GameApp::keyPressed(const OIS::KeyEvent& evt)
{

	switch(evt.key)
    {
		case OIS::KC_ESCAPE: 
        mShutDown = true;
        break;

		case OIS::KC_E:
			mDirection.y = -mMove;
			break;
 
		case OIS::KC_Q:
			mDirection.y = mMove;
			break;

		default:
        break;
    }

	return true;
}
//-------------------------------------------------------------------------------------
bool GameApp::keyReleased(const OIS::KeyEvent& evt)
{
	switch (evt.key)
	{
	case OIS::KC_W:
		mDirection = (0,0,0);
		break;
 
	case OIS::KC_S:
		mDirection = (0,0,0);
		break;
 
	case OIS::KC_A:
		mDirection = (0,0,0);
		break;
 
	case OIS::KC_D:
		mDirection = (0,0,0);
		break;
 
	case OIS::KC_E:
		mDirection.y = 0;
		break;
 
	case OIS::KC_Q:
		mDirection.y = 0;
		break;

	default:
		break;
	}

	return true;
}
//-------------------------------------------------------------------------------------
bool GameApp::mouseMoved(const OIS::MouseEvent& evt)
{
	mCamNode->yaw(Ogre::Degree(-mRotate * evt.state.X.rel), Ogre::Node::TS_WORLD);

	return true;
}
//-------------------------------------------------------------------------------------
bool GameApp::mousePressed(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
{
	return true;
}
//-------------------------------------------------------------------------------------
bool GameApp::mouseReleased(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
{
	return true;
}
//-------------------------------------------------------------------------------------

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
    INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
    int main(int argc, char *argv[])
#endif
    {
        // Create application object
        GameApp app;

        try {
            app.go();
        } catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
            MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
            std::cerr << "An exception has occured: " <<
                e.getFullDescription().c_str() << std::endl;
#endif
        }

        return 0;
    }

#ifdef __cplusplus
}
#endif
